/// ShaderFactory.cpp
/// Matthew DiBernardo (Cryptex)
/// 07.28.09
///
/// See ShaderFactory.h for usage information.

#include "ShaderFactory.h"
#include "GLSLShader.h"
#include "CGFXShader.h"

#include <fstream>

void ShaderFactory::Initialize(void)
{
	//****************************//
	// GLSL Shader Initialization //
	//****************************//
	
	// TBD: Put any GLSL Shader stuff here.
	// (Currently there isn't any! :D )


	//****************************//
	// CgFX Shader Initialization //
	//****************************//

	// IGNORE THIS SECTION 'TILL AFTER BETA
	///*
	// Create the CG Context
	cgContext = cgCreateContext();
	cgGLRegisterStates(cgContext);

	EnableCGProfiles();
}

void ShaderFactory::Shutdown(void)
{
	//**********************//
	// CgFX Shader Shutdown //
	//**********************//

	///*
	// Release the CG Profiles
	// (Might be unnecessary, but we'll do it anyway to be safe.)
	DisableCGProfiles();

	// Destroy the CG Context
	// (This will also destroy any programs associated with the context.)
	cgDestroyContext(cgContext);
	//*/
}

void ShaderFactory::EnableCGProfiles(void)
{
	// Enable ARB standard profiles
	cgGLEnableProfile(CG_PROFILE_ARBVP1);
	cgGLEnableProfile(CG_PROFILE_ARBFP1);

	// Enable NV_ profiles (nVidia specific?)
	//cgGLEnableProfile(CG_PROFILE_VP40);
	//cgGLEnableProfile(CG_PROFILE_FP40);
}

void ShaderFactory::DisableCGProfiles(void)
{
	// Disable ARB standard profiles
	cgGLDisableProfile(CG_PROFILE_ARBVP1);
	cgGLDisableProfile(CG_PROFILE_ARBFP1);

	// Disable NV_ profiles
	//cgGLDisableProfile(CG_PROFILE_VP40);
	//cgGLDisableProfile(CG_PROFILE_FP40);
}

Shader* ShaderFactory::LoadShader(const std::string fileName)
{
	// Open the shader header
	std::ifstream fin;
	fin.open(fileName.c_str(), std::ifstream::in);
	if(!fin.is_open())
		return NULL; // No Shader was loaded

	Shader* output = NULL;

	std::string headerName;
	fin >> headerName;

	if(headerName == "glsl")
	{
		output = new GLSLShader();
		((GLSLShader*)output)->SetHeaderName(fileName);

		std::string nextTag, vertName, fragName;		
		for(fin >> nextTag; nextTag == "pass"; fin >> nextTag)
		{
			fin >> vertName;
			fin >> fragName;

			((GLSLShader*)output)->LoadNextPass(vertName, fragName);
			nextTag = "";
		}
	}
	else if(headerName == "cgfx")
	{
		std::string fxName;
		fin >> fxName;

		output = new CGFXShader();
		((CGFXShader*)output)->SetHeaderName(fxName);
		
		// Pass the file to the CgFX runtime and see if it's valid
		if(!((CGFXShader*)output)->LoadEffect(cgContext, fxName))
		{
			// Effect has Failed to Validate
			delete output; // Clean up the memory we just allocated.
			output = NULL; // :(
		}
	}
	else // Unrecognized shader format
		output = NULL; // No shader was loaded

	// Close the stream and return true
	fin.close();
	return output;
}